#include <mosquitto.h>
#include "stdio.h"
#include "string.h"
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

#define ARR_SIZE(a)  (sizeof(a)/sizeof(a[0]))

#define MQTT_PORT   1883

enum topic_select {
    TOPIC_LED = 0,
    TOPIC_FAN,
    TOPIC_CURTAIN,
};
typedef enum topic_select top_sel_t;

struct mosquitto *mosq = NULL;

static const char *topic[] = {
    "led",
    "fan",
    "curtain",
};

static int mosquitoto_subscribe_topic(const char *topic, int mid, int qos)
{
    return mosquitto_subscribe(mosq, &mid, topic, qos);
}

static void mosq_on_connect_callback(struct mosquitto *mosq, void *obj, int mid)
{
    int ret = 0;

    // for (int i = 0; i < ARR_SIZE(topic); i++)
    // {
    //     if ((ret = mosquitoto_subscribe_topic(topic[i], i, mid)) == MOSQ_ERR_SUCCESS)           //订阅主题
    //     {
    //         printf("subscribe success\n");
    //     }
    //     else
    //     {
    //         fprintf(stderr, "subscribe failed %d\n", ret);
    //     }
    // }
    // if ((ret = mosquitoto_subscribe_topic("aaa", 0, 2)) == MOSQ_ERR_SUCCESS)           //订阅主题
    // {
    //     printf("subscribe success\n");
    // }
    // else
    // {
    //     fprintf(stderr, "subscribe failed %d\n", ret);
    // }
}

static void mosq_on_publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
    printf("publish message");
}

static void mosq_on_subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
{
    
}

static void mosquitto_mqtt_init(char *host, int port, int keepalive)
{
    mosquitto_lib_init();     //初始化mosquitto库

    mosq = mosquitto_new(NULL, true, NULL);     //创建一个mosquitto实例

    if (mosq == NULL)
    {
        mosquitto_destroy(mosq);    //连接失败销毁
        mosquitto_lib_cleanup();
        printf("create mosquitto obj failed\r\n");
        exit(1);
    }

    mosquitto_connect_callback_set(mosq, mosq_on_connect_callback);       //设置连接成功回到函数
    mosquitto_publish_callback_set(mosq, mosq_on_publish_callback);       //设置发布成功回调函数
    mosquitto_subscribe_callback_set(mosq, mosq_on_subscribe_callback);     //设置订阅请求成功回调函数

    int retries = 0;
    //return val MOSQ_ERR_SUCCESS
    while (mosquitto_connect(mosq, host, port, keepalive) != MOSQ_ERR_SUCCESS && retries < 5)   //如果连接失败，尝试重复连接5次
    {
        retries++;
    }

    if (retries >= 5)
    {
        printf("connect mqtt broker failed\n");
        mosquitto_destroy(mosq);    //连接失败销毁
        exit(1);
    }
    printf("connect mqtt broker\r\n");
}

int mosquitto_publish_msg(const char * topic, int payloadlen, const void *payload, int mid, int qos)
{
    return mosquitto_publish(mosq, &mid, topic, payloadlen, payload, qos, false);
}

void publish_msg_handler(top_sel_t select, char *msg)
{
    int mid;

    switch (select)
    {
        case TOPIC_LED:
        {
            mid = TOPIC_LED;
            break;
        }
        case TOPIC_FAN:
        {
            mid = TOPIC_FAN;
            break;
        }
        case TOPIC_CURTAIN:
        {
            mid = TOPIC_CURTAIN;
            break;
        }
    }
    printf("select topic :%s\n", topic[mid]);
    printf("send message : %s\n", msg);
    mosquitto_publish_msg(topic[mid], strlen(msg), msg, mid, 2);
}

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("Usage: %s <host_ip>\r\n", argv[0]); 
        exit(1);
    }

    char *host = argv[1];
    int port = MQTT_PORT;
    int keepalive = 30;

    mosquitto_mqtt_init(host, port, keepalive);
   
    if (mosquitto_loop_start(mosq) != MOSQ_ERR_SUCCESS)
    {
        printf("failed to Call this once to start a new thread to process network traffic\n");
        mosquitto_destroy(mosq);      //连接失败销毁
        mosquitto_lib_cleanup();
        exit(1);
    }

    int select  = 0;
    char msg[1024] = {0};

    sleep(1);
    while (1)
    {
        printf("please select topic, 0 - led 1 - fan 2 - curtain : ");
        scanf("%d", &select);
        printf("please input message to send：");
        scanf("%s", msg);
        publish_msg_handler((top_sel_t)select, msg);
    }

    return 0;
}